package com.zj.android.activity

import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.hardware.Camera
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.webkit.MimeTypeMap
import android.widget.FrameLayout
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.core.net.toFile
import com.zj.android.BR
import com.zj.android.R
import com.zj.android.databinding.ActivityCameraBinding
import com.zj.android.model.CameraViewModel
import com.zj.common.activity.BaseActivity
import com.zj.common.expand.screenHeight
import com.zj.common.expand.screenWidth
import com.zj.common.expand.statusBarHeight
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

class CameraActivity : BaseActivity<CameraViewModel, ActivityCameraBinding>() {

    companion object {
        private const val RATIO_4_3_VALUE = 4.0 / 3.0
        private const val RATIO_16_9_VALUE = 16.0 / 9.0
    }

    private var lensFacing: Int = CameraSelector.LENS_FACING_BACK
    private var cameraProvider: ProcessCameraProvider? = null

    private var imageCapture: ImageCapture? = null
    private lateinit var cameraExecutor: ExecutorService

    override fun layoutId(): Int {
        return R.layout.activity_camera
    }

    override fun initData(savedInstanceState: Bundle?) {
        // 设置状态栏顶部距离
        val toolBar: FrameLayout = binding.root.findViewById(R.id.title_bar)
        toolBar.post {
            val layoutParams: FrameLayout.LayoutParams =
                toolBar.layoutParams as FrameLayout.LayoutParams
            layoutParams.topMargin = baseContext.statusBarHeight()
            toolBar.layoutParams = layoutParams
        }

        cameraExecutor = Executors.newSingleThreadExecutor()
        binding.apply {
            back.setOnClickListener { finish() }
            cameraSwitch.setOnClickListener {
                lensFacing = if (CameraSelector.LENS_FACING_FRONT == lensFacing) {
                    CameraSelector.LENS_FACING_BACK
                } else {
                    CameraSelector.LENS_FACING_FRONT
                }
                bindPreview()
            }

            cameraBnt.setOnClickListener {
                imageCapture?.let {
                    // 创建输出文件以保存图像
                    val photoFile = createFile(
                        getOutputDirectory(baseContext),
                        "yyyy-MM-dd-HH-mm-ss-SSS",
                        ".png"
                    )
                    // 设置图像捕获元数据
                    val metadata = ImageCapture.Metadata().apply {
                        // 使用前置摄像头时的镜像
                        isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT
                    }
                    // 创建包含文件 + 元数据的输出选项对象
                    val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile)
                        .setMetadata(metadata)
                        .build()

                    // Setup image capture listener which is triggered after photo has been taken
                    it.takePicture(
                        outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {
                            override fun onError(exc: ImageCaptureException) {
                                //Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
                            }

                            override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                                val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
                                //Log.d(TAG, "Photo capture succeeded: $savedUri")

                                // We can only change the foreground Drawable using API level 23+ API
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                                    // Update the gallery thumbnail with latest picture taken
                                    //setGalleryThumbnail(savedUri)
                                }

                                // Implicit broadcasts will be ignored for devices running API level >= 24
                                // so if you only target API level 24+ you can remove this statement
                                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
                                    baseContext.sendBroadcast(
                                        Intent(Camera.ACTION_NEW_PICTURE, savedUri)
                                    )
                                }

                                // If the folder selected is an external media directory, this is
                                // unnecessary but otherwise other apps will not be able to access our
                                // images unless we scan them using [MediaScannerConnection]
                                val mimeType = MimeTypeMap.getSingleton()
                                    .getMimeTypeFromExtension(savedUri.toFile().extension)
                                MediaScannerConnection.scanFile(
                                    baseContext,
                                    arrayOf(savedUri.toFile().absolutePath),
                                    arrayOf(mimeType)
                                ) { _, uri ->
                                    //Log.d(TAG, "Image capture scanned into media store: $uri")
                                }
                            }
                        })

                    // We can only change the foreground Drawable using API level 23+ API
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        // Display flash animation to indicate that photo was captured
                        binding.root.postDelayed({
                            binding.root.foreground = ColorDrawable(Color.WHITE)
                            binding.root.postDelayed(
                                { binding.root.foreground = null },
                                50L
                            )
                        }, 100L)
                    }
                }
            }


        }
    }

    private fun bindPreview() {
        val rotation = binding?.viewFinder?.display?.rotation ?: 0
        val aspectRatio = aspectRatio(baseContext.screenWidth(), baseContext.screenHeight())

        val preview: Preview = Preview.Builder()
            // 我们要求纵横比但没有分辨率
            .setTargetAspectRatio(aspectRatio)
            // 设置初始目标旋转
            .setTargetRotation(rotation)
            .build()

        val cameraSelector: CameraSelector = CameraSelector.Builder()
            .requireLensFacing(lensFacing)
            .build()

        imageCapture = ImageCapture.Builder()
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
            // CameraX 针对最适合我们用例的任何特定分辨率进行优化
            .setTargetAspectRatio(aspectRatio)
            // 在此用例的生命周期中
            .setTargetRotation(rotation)
            .build()

        val imageAnalysis = ImageAnalysis.Builder()
            // 我们要求纵横比但没有分辨率
            .setTargetAspectRatio(aspectRatio)
            // 在此用例的生命周期中
            .setTargetRotation(rotation)
            .build()

        // 必须在重新绑定用例之前解除绑定它们
        cameraProvider?.unbindAll()
        cameraProvider?.bindToLifecycle(
            this,
            cameraSelector,
            preview,
            imageCapture,
            imageAnalysis
        )
        preview.setSurfaceProvider(binding.viewFinder.surfaceProvider)
    }

    /** 如果设备有可用的后置摄像头，则返回 true。否则为假 */
    private fun hasBackCamera(): Boolean {
        return cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
    }

    /** 如果设备有可用的前置摄像头，则返回 true。否则为假 */
    private fun hasFrontCamera(): Boolean {
        return cameraProvider?.hasCamera(CameraSelector.DEFAULT_FRONT_CAMERA) ?: false
    }

    private fun aspectRatio(width: Int, height: Int): Int {
        val previewRatio = max(width, height).toDouble() / min(width, height)
        if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
            return AspectRatio.RATIO_4_3
        }
        return AspectRatio.RATIO_16_9
    }

    private fun getOutputDirectory(context: Context): File {
        val appContext = context.applicationContext
        val mediaDir = context.externalMediaDirs.firstOrNull()?.let {
            File(it, appContext.resources.getString(R.string.app_name)).apply { mkdirs() }
        }
        return if (mediaDir != null && mediaDir.exists()) {
            mediaDir
        } else {
            appContext.filesDir
        }
    }

    private fun createFile(baseFolder: File, format: String, extension: String) =
        File(
            baseFolder, SimpleDateFormat(format, Locale.US)
                .format(System.currentTimeMillis()) + extension
        )

    override fun variableId(): Int {
        return BR.camera
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (hasFocus) {
            // 初始化获取ProcessCameraProvider实例对象
            val instance = ProcessCameraProvider.getInstance(this)
            instance.addListener({
                cameraProvider = instance.get()
                // 根据可用的相机选择 lensFacing
                lensFacing = when {
                    hasBackCamera() -> CameraSelector.LENS_FACING_BACK
                    hasFrontCamera() -> CameraSelector.LENS_FACING_FRONT
                    else -> throw IllegalStateException("Back and front camera are unavailable")
                }
                bindPreview()
            }, ContextCompat.getMainExecutor(this))
        }
    }

    override fun onDestroy() {
        cameraExecutor.shutdown()
        cameraProvider?.unbindAll()
        super.onDestroy()
    }
}